package com.example.handheld4_gsignal_app.services;

import android.content.Context;
import android.util.Log;
import com.example.handheld4_gsignal_app.data.SignalRecord;
import com.example.handheld4_gsignal_app.network.ApiClient;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.*;

/**
 * 可视化服务 - 提供趋势图和热力图数据处理功能
 */
public class VisualizationService {
    
    private static final String TAG = "VisualizationService";
    private Context context;
    private ApiClient apiClient;
    private Gson gson;
    
    public VisualizationService(Context context) {
        this.context = context;
        this.apiClient = new ApiClient();
        this.gson = new Gson();
    }
    
    /**
     * 趋势图数据点
     */
    public static class TrendDataPoint {
        private String timestamp;
        private double value;
        private Double min;
        private Double max;
        private Double std;
        private Integer count;
        
        // Getters and Setters
        public String getTimestamp() { return timestamp; }
        public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
        
        public double getValue() { return value; }
        public void setValue(double value) { this.value = value; }
        
        public Double getMin() { return min; }
        public void setMin(Double min) { this.min = min; }
        
        public Double getMax() { return max; }
        public void setMax(Double max) { this.max = max; }
        
        public Double getStd() { return std; }
        public void setStd(Double std) { this.std = std; }
        
        public Integer getCount() { return count; }
        public void setCount(Integer count) { this.count = count; }
    }
    
    /**
     * 趋势图数据
     */
    public static class TrendData {
        private String trendId;
        private String recordId;
        private String deviceId;
        private String metricName;
        private List<TrendDataPoint> timeSeries;
        private String aggregationType;
        private String createdAt;
        
        // Getters and Setters
        public String getTrendId() { return trendId; }
        public void setTrendId(String trendId) { this.trendId = trendId; }
        
        public String getRecordId() { return recordId; }
        public void setRecordId(String recordId) { this.recordId = recordId; }
        
        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
        
        public String getMetricName() { return metricName; }
        public void setMetricName(String metricName) { this.metricName = metricName; }
        
        public List<TrendDataPoint> getTimeSeries() { return timeSeries; }
        public void setTimeSeries(List<TrendDataPoint> timeSeries) { this.timeSeries = timeSeries; }
        
        public String getAggregationType() { return aggregationType; }
        public void setAggregationType(String aggregationType) { this.aggregationType = aggregationType; }
        
        public String getCreatedAt() { return createdAt; }
        public void setCreatedAt(String createdAt) { this.createdAt = createdAt; }
    }
    
    /**
     * 热力图数据
     */
    public static class HeatmapData {
        private String heatmapId;
        private String recordId;
        private String deviceId;
        private String dataType;
        private int width;
        private int height;
        private List<List<Double>> dataPoints;
        private Double minValue;
        private Double maxValue;
        private String colorScheme;
        private String createdAt;
        
        // Getters and Setters
        public String getHeatmapId() { return heatmapId; }
        public void setHeatmapId(String heatmapId) { this.heatmapId = heatmapId; }
        
        public String getRecordId() { return recordId; }
        public void setRecordId(String recordId) { this.recordId = recordId; }
        
        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
        
        public String getDataType() { return dataType; }
        public void setDataType(String dataType) { this.dataType = dataType; }
        
        public int getWidth() { return width; }
        public void setWidth(int width) { this.width = width; }
        
        public int getHeight() { return height; }
        public void setHeight(int height) { this.height = height; }
        
        public List<List<Double>> getDataPoints() { return dataPoints; }
        public void setDataPoints(List<List<Double>> dataPoints) { this.dataPoints = dataPoints; }
        
        public Double getMinValue() { return minValue; }
        public void setMinValue(Double minValue) { this.minValue = minValue; }
        
        public Double getMaxValue() { return maxValue; }
        public void setMaxValue(Double maxValue) { this.maxValue = maxValue; }
        
        public String getColorScheme() { return colorScheme; }
        public void setColorScheme(String colorScheme) { this.colorScheme = colorScheme; }
        
        public String getCreatedAt() { return createdAt; }
        public void setCreatedAt(String createdAt) { this.createdAt = createdAt; }
    }
    
    /**
     * 回调接口
     */
    public interface TrendDataCallback {
        void onSuccess(TrendData trendData);
        void onError(String error);
    }
    
    public interface HeatmapDataCallback {
        void onSuccess(HeatmapData heatmapData);
        void onError(String error);
    }
    
    /**
     * 生成趋势图数据（服务器端）
     */
    public void generateTrendData(List<SignalRecord> signalData, String metricName, 
                                 String aggregationType, TrendDataCallback callback) {
        try {
            Map<String, Object> request = new HashMap<>();
            request.put("signal_data", convertSignalRecordsToMap(signalData));
            request.put("metric_name", metricName);
            request.put("aggregation_type", aggregationType);
            
            String requestJson = gson.toJson(request);
            Log.d(TAG, "生成趋势图数据请求: " + metricName);
            
            apiClient.post("/api/v2/visualization/trend", requestJson, new ApiClient.ApiCallback() {
                @Override
                public void onSuccess(String response) {
                    try {
                        TrendData trendData = gson.fromJson(response, TrendData.class);
                        Log.d(TAG, "趋势图数据生成成功: " + trendData.getTrendId());
                        callback.onSuccess(trendData);
                    } catch (Exception e) {
                        Log.e(TAG, "解析趋势图数据失败", e);
                        callback.onError("解析结果失败: " + e.getMessage());
                    }
                }
                
                @Override
                public void onError(String error) {
                    Log.e(TAG, "趋势图数据生成失败: " + error);
                    callback.onError(error);
                }
            });
            
        } catch (Exception e) {
            Log.e(TAG, "趋势图数据生成请求失败", e);
            callback.onError("生成请求失败: " + e.getMessage());
        }
    }
    
    /**
     * 生成热力图数据（服务器端）
     */
    public void generateHeatmapData(List<SignalRecord> signalData, String dataType, 
                                   int width, int height, String colorScheme, HeatmapDataCallback callback) {
        try {
            Map<String, Object> request = new HashMap<>();
            request.put("signal_data", convertSignalRecordsToMap(signalData));
            request.put("data_type", dataType);
            request.put("width", width);
            request.put("height", height);
            request.put("color_scheme", colorScheme);
            
            String requestJson = gson.toJson(request);
            Log.d(TAG, "生成热力图数据请求: " + dataType);
            
            apiClient.post("/api/v2/visualization/heatmap", requestJson, new ApiClient.ApiCallback() {
                @Override
                public void onSuccess(String response) {
                    try {
                        HeatmapData heatmapData = gson.fromJson(response, HeatmapData.class);
                        Log.d(TAG, "热力图数据生成成功: " + heatmapData.getHeatmapId());
                        callback.onSuccess(heatmapData);
                    } catch (Exception e) {
                        Log.e(TAG, "解析热力图数据失败", e);
                        callback.onError("解析结果失败: " + e.getMessage());
                    }
                }
                
                @Override
                public void onError(String error) {
                    Log.e(TAG, "热力图数据生成失败: " + error);
                    callback.onError(error);
                }
            });
            
        } catch (Exception e) {
            Log.e(TAG, "热力图数据生成请求失败", e);
            callback.onError("生成请求失败: " + e.getMessage());
        }
    }
    
    /**
     * 本地生成趋势图数据（简化版）
     */
    public TrendData generateTrendDataLocally(List<SignalRecord> signalData, String metricName) {
        TrendData trendData = new TrendData();
        trendData.setTrendId("local_trend_" + System.currentTimeMillis());
        trendData.setRecordId("local_record");
        trendData.setDeviceId("local_device");
        trendData.setMetricName(metricName);
        trendData.setAggregationType("raw");
        trendData.setCreatedAt(String.valueOf(System.currentTimeMillis()));
        
        List<TrendDataPoint> timeSeries = new ArrayList<>();
        
        for (SignalRecord record : signalData) {
            TrendDataPoint point = new TrendDataPoint();
            point.setTimestamp(record.getCollectedAt());
            
            // 根据指标名称获取值
            switch (metricName) {
                case "signal_strength":
                    point.setValue(record.getSignalStrength());
                    break;
                case "rsrp":
                    point.setValue(record.getRsrp() != 0 ? record.getRsrp() : -120);
                    break;
                case "rsrq":
                    point.setValue(record.getRsrq() != 0.0 ? record.getRsrq() : -20);
                    break;
                case "snr":
                    point.setValue(record.getSnr() != 0.0 ? record.getSnr() : 0);
                    break;
                default:
                    point.setValue(record.getSignalStrength());
                    break;
            }
            
            timeSeries.add(point);
        }
        
        trendData.setTimeSeries(timeSeries);
        return trendData;
    }
    
    /**
     * 本地生成热力图数据（简化版）
     */
    public HeatmapData generateHeatmapDataLocally(List<SignalRecord> signalData, String dataType, 
                                                 int width, int height, String colorScheme) {
        HeatmapData heatmapData = new HeatmapData();
        heatmapData.setHeatmapId("local_heatmap_" + System.currentTimeMillis());
        heatmapData.setRecordId("local_record");
        heatmapData.setDeviceId("local_device");
        heatmapData.setDataType(dataType);
        heatmapData.setWidth(width);
        heatmapData.setHeight(height);
        heatmapData.setColorScheme(colorScheme);
        heatmapData.setCreatedAt(String.valueOf(System.currentTimeMillis()));
        
        // 生成模拟热力图数据
        List<List<Double>> dataPoints = generateMockHeatmapData(dataType, width, height, signalData);
        heatmapData.setDataPoints(dataPoints);
        
        // 计算数据范围
        double minValue = Double.MAX_VALUE;
        double maxValue = Double.MIN_VALUE;
        
        for (List<Double> row : dataPoints) {
            for (Double value : row) {
                minValue = Math.min(minValue, value);
                maxValue = Math.max(maxValue, value);
            }
        }
        
        heatmapData.setMinValue(minValue);
        heatmapData.setMaxValue(maxValue);
        
        return heatmapData;
    }
    
    /**
     * 生成模拟热力图数据
     */
    private List<List<Double>> generateMockHeatmapData(String dataType, int width, int height, 
                                                      List<SignalRecord> signalData) {
        List<List<Double>> dataPoints = new ArrayList<>();
        
        // 根据数据类型生成不同的热力图
        switch (dataType) {
            case "signal_strength":
                dataPoints = generateSignalStrengthHeatmap(width, height, signalData);
                break;
            case "frequency":
                dataPoints = generateFrequencyHeatmap(width, height);
                break;
            case "time_frequency":
                dataPoints = generateTimeFrequencyHeatmap(width, height, signalData);
                break;
            default:
                dataPoints = generateSignalStrengthHeatmap(width, height, signalData);
                break;
        }
        
        return dataPoints;
    }
    
    /**
     * 生成信号强度热力图
     */
    private List<List<Double>> generateSignalStrengthHeatmap(int width, int height, List<SignalRecord> signalData) {
        List<List<Double>> dataPoints = new ArrayList<>();
        
        // 计算位置范围
        double minLat = Double.MAX_VALUE, maxLat = Double.MIN_VALUE;
        double minLng = Double.MAX_VALUE, maxLng = Double.MIN_VALUE;
        
        for (SignalRecord record : signalData) {
            minLat = Math.min(minLat, record.getLatitude());
            maxLat = Math.max(maxLat, record.getLatitude());
            minLng = Math.min(minLng, record.getLongitude());
            maxLng = Math.max(maxLng, record.getLongitude());
        }
        
        // 如果数据不足，使用默认范围
        if (minLat == Double.MAX_VALUE) {
            minLat = 39.9;
            maxLat = 40.0;
            minLng = 116.3;
            maxLng = 116.4;
        }
        
        // 生成网格数据
        for (int i = 0; i < height; i++) {
            List<Double> row = new ArrayList<>();
            double lat = minLat + (maxLat - minLat) * i / height;
            
            for (int j = 0; j < width; j++) {
                double lng = minLng + (maxLng - minLng) * j / width;
                
                // 计算到最近数据点的距离，进行插值
                double minDistance = Double.MAX_VALUE;
                double nearestSignal = -120.0;
                
                for (SignalRecord record : signalData) {
                    double distance = Math.sqrt(
                        Math.pow(record.getLatitude() - lat, 2) + 
                        Math.pow(record.getLongitude() - lng, 2)
                    );
                    
                    if (distance < minDistance) {
                        minDistance = distance;
                        nearestSignal = record.getSignalStrength();
                    }
                }
                
                // 添加一些噪声使热力图更平滑
                double noise = (Math.random() - 0.5) * 5;
                row.add(nearestSignal + noise);
            }
            
            dataPoints.add(row);
        }
        
        return dataPoints;
    }
    
    /**
     * 生成频率热力图
     */
    private List<List<Double>> generateFrequencyHeatmap(int width, int height) {
        List<List<Double>> dataPoints = new ArrayList<>();
        
        for (int i = 0; i < height; i++) {
            List<Double> row = new ArrayList<>();
            
            for (int j = 0; j < width; j++) {
                // 模拟频谱数据
                double freqRatio = (double) j / width;
                double timeRatio = (double) i / height;
                
                // 模拟多峰频谱
                double value = -120 + 50 * Math.exp(-((freqRatio - 0.3) * (freqRatio - 0.3) + (timeRatio - 0.5) * (timeRatio - 0.5)) * 10);
                value += 30 * Math.exp(-((freqRatio - 0.7) * (freqRatio - 0.7) + (timeRatio - 0.3) * (timeRatio - 0.3)) * 15);
                value += 20 * Math.exp(-((freqRatio - 0.5) * (freqRatio - 0.5) + (timeRatio - 0.8) * (timeRatio - 0.8)) * 8);
                
                row.add(Math.max(-120, Math.min(0, value)));
            }
            
            dataPoints.add(row);
        }
        
        return dataPoints;
    }
    
    /**
     * 生成时频热力图
     */
    private List<List<Double>> generateTimeFrequencyHeatmap(int width, int height, List<SignalRecord> signalData) {
        List<List<Double>> dataPoints = new ArrayList<>();
        
        for (int i = 0; i < height; i++) {
            List<Double> row = new ArrayList<>();
            double timeRatio = (double) i / height;
            
            // 找到对应时间的数据点
            int dataIndex = (int) (timeRatio * signalData.size());
            if (dataIndex >= signalData.size()) {
                dataIndex = signalData.size() - 1;
            }
            
            double signalStrength = signalData.get(dataIndex).getSignalStrength();
            
            for (int j = 0; j < width; j++) {
                double freqRatio = (double) j / width;
                
                // 模拟时频分析结果
                double baseStrength = signalStrength;
                double freqModulation = 10 * Math.sin(2 * Math.PI * freqRatio * 3); // 3个主要频率分量
                double noise = (Math.random() - 0.5) * 2; // 噪声
                
                double value = baseStrength + freqModulation + noise;
                row.add(Math.max(-120, Math.min(0, value)));
            }
            
            dataPoints.add(row);
        }
        
        return dataPoints;
    }
    
    /**
     * 转换信号记录为Map格式
     */
    private List<Map<String, Object>> convertSignalRecordsToMap(List<SignalRecord> records) {
        List<Map<String, Object>> data = new ArrayList<>();
        for (SignalRecord record : records) {
            Map<String, Object> recordMap = new HashMap<>();
            recordMap.put("device_id", record.getDeviceId());
            recordMap.put("signal_strength", record.getSignalStrength());
            recordMap.put("latitude", record.getLatitude());
            recordMap.put("longitude", record.getLongitude());
            recordMap.put("collected_at", record.getCollectedAt());
            recordMap.put("network_type", record.getNetworkType());
            recordMap.put("operator_name", record.getOperatorName());
            recordMap.put("cell_id", record.getCellId());
            recordMap.put("rsrp", record.getRsrp());
            recordMap.put("rsrq", record.getRsrq());
            recordMap.put("rssi", record.getRssi());
            recordMap.put("snr", record.getSnr());
            data.add(recordMap);
        }
        return data;
    }
}